﻿using Cube.Data;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CubeForm.AI
{
    class SecondLayer : IPattenMatch
    {
        Cube.Data.Cube cube;
        PattenManager patten;
        List<PositionVector> AvailablePositions = new List<PositionVector>
        {
            new PositionVector(1,0,1),
            new PositionVector(0,-1,1),
            new PositionVector(-1,0,1),
            new PositionVector(0,1,1)
        };

        public event PattenMatchedDelegate PattenMatched;

        public SecondLayer(Cube.Data.Cube cube)
        {
            this.cube = cube;
            patten = new PattenManager(cube);
        }
        public void Invoke()
        {
            while (TrySetAnAvailableBlock())
            {
                RotateCubeToRightCase();
                var second_layer_case = JudgeCase();
                switch (second_layer_case)
                {
                    case SecondLayerCase.Case1:
                        DoPatten1();
                        break;
                    case SecondLayerCase.Case2:
                        DoPatten2();
                        break;
                }
                Debug.WriteLine("A SideBlock Done.\n");
            }
            PattenMatched?.Invoke(patten.GetRecord());
        }

        /// <summary>
        /// 执行公式一
        /// </summary>
        private void DoPatten1()
        {
            patten.R();patten.U();patten.R();patten.U();patten.R();
            patten._U();patten._R();patten._U();patten._R();
        }
        /// <summary>
        /// 执行公式二
        /// </summary>
        private void DoPatten2()
        {
            patten._R(); patten._U(); patten._R(); patten._U(); patten._R();
            patten.U(); patten.R(); patten.U(); patten.R();
        }

        /// <summary>
        /// 将一个可用的中层棱块放到目标位置(1,0,1)
        /// </summary>
        private bool TrySetAnAvailableBlock()
        {
            // 顶面颜色
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            // 优先在顶面寻找
            var found_in_top = false;
            foreach(var position in AvailablePositions)
            {
                if (cube[position].X == top_color || cube[position].Y == top_color || cube[position].Z == top_color)
                {
                    // 包含顶面颜色，说明不属于中层棱块
                    continue;
                }
                //找到了中层棱块
                Debug.Write("Found Side On Top: " + position.X + "," + position.Y + "," + position.Z);
                found_in_top = true;
                var selected_index = cube.FindCubeByPosition(position);
                var selected_block = cube[selected_index];
                while(!selected_block.Position.Equals(new PositionVector(1, 0, 1)))
                {
                    // 循环进行U操作，直到转到目标位置
                    patten.U();
                }
                Debug.WriteLine("...Roteted to (1,0,1).");
                return true;
            }
            // 顶面未找到，则尝试旋转魔方，找一个属于中层但位置错误的棱块，用公式将其弄出来
            if (!found_in_top)
            {
                for(var i = 0; i < 4; i++)
                {
                    var front_color = cube[new PositionVector(0, 1, 0)].Y;
                    var right_color = cube[new PositionVector(1, 0, 0)].X;
                    
                    var cheking_positon = new PositionVector(1, 1, 0);
                    if (cube[cheking_positon].X != top_color && cube[cheking_positon].Y != top_color)
                    {
                        // 说明此棱块是中层棱块，下一步判断是否位置错误
                        if (cube[cheking_positon].X != right_color || cube[cheking_positon].Y != front_color)
                        {
                            Debug.Write("Found Side In Middle...");
                            DoPatten2();    //利用公式二将错误棱块换到顶层
                            patten.U(); patten.U(); //再加两个U将调出来的棱块置于目标位置
                            Debug.WriteLine("Patten used.");
                            return true;
                        }
                    }
                    patten.y(); //未找到，旋转魔方到下一个面找
                }
            }
            Debug.WriteLine("No available sideblocks.");
            return false;
        }

        /// <summary>
        /// 参考目标位置准备还原的棱块，调整中层和底层的位置
        /// </summary>
        private void RotateCubeToRightCase()
        {
            while(cube[new PositionVector(1,0,1)].X!=cube[new PositionVector(1, 0, 0)].X)
            {
                patten.MU();
                patten.D();
            }
            Debug.Write("Case ready:");
        }

        /// <summary>
        /// 判断应该使用哪个公式
        /// </summary>
        /// <returns></returns>
        private SecondLayerCase JudgeCase()
        {
            var front_color = cube[new PositionVector(0, 1, 0)].Y;
            if(cube[new PositionVector(1, 0, 1)].Z == front_color)
            {
                Debug.WriteLine("Case2");
                return SecondLayerCase.Case2;
            }
            Debug.WriteLine("Case1");
            return SecondLayerCase.Case1;
        }

        enum SecondLayerCase
        {
            Case1,
            Case2
        }
    }
}
